<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>音程听力训练工具</title>
    <style>
        body {
            font-family: 'Arial', sans-serif;
            background: linear-gradient(135deg, #1a1a1a 0%, #2d2d2d 100%);
            margin: 0;
            padding: 20px;
            min-height: 100vh;
            display: flex;
            justify-content: center;
            align-items: center;
            color: #e0e0e0;
        }
        
        .container {
            background: rgba(45, 45, 45, 0.95);
            border-radius: 20px;
            padding: 30px;
            box-shadow: 0 20px 40px rgba(0, 0, 0, 0.3);
            backdrop-filter: blur(10px);
            text-align: center;
            max-width: 500px;
            width: 100%;
            border: 1px solid #404040;
        }
        
        h1 {
            color: #ffffff;
            margin-bottom: 30px;
            font-size: 2em;
        }
        
        .control-section {
            margin-bottom: 30px;
        }
        
        .button {
            background: linear-gradient(45deg, #2d5a2d, #1e3f1e);
            border: 1px solid #2d5a2d;
            color: #e0e0e0;
            padding: 12px 24px;
            text-align: center;
            text-decoration: none;
            display: inline-block;
            font-size: 16px;
            margin: 4px 2px;
            cursor: pointer;
            border-radius: 25px;
            transition: all 0.3s ease;
            box-shadow: 0 4px 15px rgba(45, 90, 45, 0.3);
            font-weight: bold;
            text-transform: uppercase;
            letter-spacing: 1px;
        }
        
        .button:hover {
            transform: translateY(-2px);
            box-shadow: 0 6px 20px rgba(45, 90, 45, 0.4);
            background: linear-gradient(45deg, #4CAF50, #45a049);
            border-color: #4CAF50;
            color: white;
        }
        
        .button:active {
            transform: translateY(0);
        }
        
        .button.stop {
            background: linear-gradient(45deg, #5d2d2d, #3f1e1e);
            border-color: #5d2d2d;
        }
        
        .button.stop:hover {
            background: linear-gradient(45deg, #f44336, #d32f2f);
            border-color: #f44336;
            box-shadow: 0 6px 20px rgba(244, 67, 54, 0.4);
        }
        
        .button.play-reference {
            background: linear-gradient(45deg, #2d4a5d, #1e3240);
            border-color: #2d4a5d;
        }
        
        .button.play-reference:hover {
            background: linear-gradient(45deg, #2196F3, #1976D2);
            border-color: #2196F3;
            box-shadow: 0 6px 20px rgba(33, 150, 243, 0.4);
        }
        
        .speed-control {
            margin: 20px 0;
        }
        
        .speed-control label {
            display: block;
            margin-bottom: 10px;
            font-weight: bold;
            color: #e0e0e0;
        }
        
        .speed-slider {
            width: 300px;
            height: 6px;
            border-radius: 5px;
            background: #ddd;
            outline: none;
            -webkit-appearance: none;
        }
        
        .speed-slider::-webkit-slider-thumb {
            -webkit-appearance: none;
            appearance: none;
            width: 20px;
            height: 20px;
            border-radius: 50%;
            background: #4CAF50;
            cursor: pointer;
        }
        
        .speed-value {
            font-size: 18px;
            color: #b0b0b0;
            margin-top: 5px;
        }
        
        .current-interval {
            background: rgba(64, 64, 64, 0.8);
            border-radius: 10px;
            padding: 20px;
            margin: 20px 0;
            border-left: 4px solid #4CAF50;
            border: 1px solid #555;
        }
        
        .interval-display {
            font-size: 24px;
            font-weight: bold;
            color: #ffffff;
            margin-bottom: 10px;
        }
        
        .notes-display {
            font-size: 16px;
            color: #b0b0b0;
        }
        
        .progress-bar {
            width: 100%;
            height: 8px;
            background: #e0e0e0;
            border-radius: 4px;
            overflow: hidden;
            margin: 20px 0;
        }
        
        .progress-fill {
            height: 100%;
            background: linear-gradient(90deg, #4CAF50, #45a049);
            width: 0%;
            transition: width 0.1s ease;
        }
        
        .status {
            font-size: 16px;
            color: #e0e0e0;
            margin: 10px 0;
        }
    </style>
</head>
<body>
    <div class="container">
        <h1> 音程听力训练</h1>
        
        <div class="control-section">
            <button class="button play-reference" onclick="playReference()">播放基准音 (A4)</button>
            <button class="button" onclick="startTraining()">开始训练</button>
            <button class="button stop" onclick="stopTraining()">停止训练</button>
        </div>
        
        <div class="speed-control">
            <label for="speedSlider">训练节奏 (秒/题)</label>
            <input type="range" id="speedSlider" class="speed-slider" min="2" max="10" value="4" oninput="updateSpeed(this.value)">
            <div class="speed-value" id="speedValue">4 秒/题</div>
        </div>
        
        <div class="progress-bar">
            <div class="progress-fill" id="progressFill"></div>
        </div>
        
        <div class="status" id="status">点击"开始训练"开始练习</div>
        
        <div class="current-interval" id="intervalDisplay" style="display: none;">
            <div class="interval-display" id="intervalName">-</div>
            <div class="notes-display" id="intervalNotes">-</div>
        </div>
    </div>

    <script src="https://cdnjs.cloudflare.com/ajax/libs/tone.js/14.8.49/Tone.js"></script>
    <script>
        let synth;
        let audioContext;
        let isTraining = false;
        let currentInterval = 0;
        let trainingSpeed = 4; // seconds
        let intervalTimer;
        let progressTimer;
        let useFallback = false; // 是否使用备用音频方案
        
        // 音程定义 (以半音为单位)
        const intervals = {
            '纯一度': 0,
            '小二度': 1,
            '大二度': 2,
            '小三度': 3,
            '大三度': 4,
            '纯四度': 5,
            '增四度/减五度': 6,
            '纯五度': 7,
            '小六度': 8,
            '大六度': 9,
            '小七度': 10,
            '大七度': 11,
            '纯八度': 12
        };
        
        // 检查Tone.js是否加载成功
        function checkToneJS() {
            return typeof Tone !== 'undefined' && Tone.Synth;
        }
        
        // 初始化备用音频上下文
        async function initFallbackAudio() {
            try {
                audioContext = new (window.AudioContext || window.webkitAudioContext)();
                if (audioContext.state === 'suspended') {
                    await audioContext.resume();
                }
                console.log('备用音频上下文已启动');
                return true;
            } catch (error) {
                console.error('备用音频初始化失败:', error);
                return false;
            }
        }
        
        // 使用备用方案播放音符（钢琴音色）
        function playNoteWithFallback(frequency, duration = 0.5) {
            if (!audioContext) return;
            
            // 创建钢琴音色的复合波形
            const oscillator1 = audioContext.createOscillator();
            const oscillator2 = audioContext.createOscillator();
            const oscillator3 = audioContext.createOscillator();
            
            const gainNode = audioContext.createGain();
            const gain1 = audioContext.createGain();
            const gain2 = audioContext.createGain();
            const gain3 = audioContext.createGain();
            
            // 基频
            oscillator1.frequency.setValueAtTime(frequency, audioContext.currentTime);
            oscillator1.type = 'triangle';
            gain1.gain.setValueAtTime(0.6, audioContext.currentTime);
            
            // 二次谐波
            oscillator2.frequency.setValueAtTime(frequency * 2, audioContext.currentTime);
            oscillator2.type = 'sine';
            gain2.gain.setValueAtTime(0.3, audioContext.currentTime);
            
            // 三次谐波
            oscillator3.frequency.setValueAtTime(frequency * 3, audioContext.currentTime);
            oscillator3.type = 'sine';
            gain3.gain.setValueAtTime(0.1, audioContext.currentTime);
            
            // 连接音频节点
            oscillator1.connect(gain1);
            oscillator2.connect(gain2);
            oscillator3.connect(gain3);
            
            gain1.connect(gainNode);
            gain2.connect(gainNode);
            gain3.connect(gainNode);
            gainNode.connect(audioContext.destination);
            
            // 钢琴式的音量包络
            gainNode.gain.setValueAtTime(0, audioContext.currentTime);
            gainNode.gain.linearRampToValueAtTime(0.4, audioContext.currentTime + 0.02);
            gainNode.gain.exponentialRampToValueAtTime(0.2, audioContext.currentTime + 0.1);
            gainNode.gain.exponentialRampToValueAtTime(0.01, audioContext.currentTime + duration);
            
            // 启动和停止振荡器
            const startTime = audioContext.currentTime;
            const stopTime = startTime + duration;
            
            [oscillator1, oscillator2, oscillator3].forEach(osc => {
                osc.start(startTime);
                osc.stop(stopTime);
            });
        }
        
        // 音符名转频率
        function noteToFrequency(note) {
            const noteMap = {
                'C': -9, 'C#': -8, 'D': -7, 'D#': -6, 'E': -5, 'F': -4,
                'F#': -3, 'G': -2, 'G#': -1, 'A': 0, 'A#': 1, 'B': 2
            };
            
            const match = note.match(/([A-G]#?)([0-9])/);
            if (!match) return 440; // 默认A4
            
            const noteName = match[1];
            const octave = parseInt(match[2]);
            
            const semitoneOffset = noteMap[noteName] + (octave - 4) * 12;
            return 440 * Math.pow(2, semitoneOffset / 12);
        }
        
        // 初始化音频
        async function initAudio() {
            try {
                // 首先尝试使用Tone.js
                if (checkToneJS()) {
                    if (!synth) {
                        // 使用钢琴音色的合成器
                        synth = new Tone.PolySynth(Tone.Synth, {
                            oscillator: {
                                type: "triangle"
                            },
                            envelope: {
                                attack: 0.02,
                                decay: 0.1,
                                sustain: 0.3,
                                release: 1
                            },
                            volume: -10
                        }).toDestination();
                        
                        // 添加混响效果模拟钢琴的空间感
                        const reverb = new Tone.Reverb({
                            decay: 1.5,
                            wet: 0.3
                        }).toDestination();
                        
                        synth.connect(reverb);
                    }
                    
                    // 启动音频上下文
                    if (Tone.context.state !== 'running') {
                        await Tone.start();
                        console.log('Tone.js音频上下文已启动');
                    }
                    useFallback = false;
                } else {
                    throw new Error('Tone.js未加载');
                }
            } catch (error) {
                console.warn('Tone.js初始化失败，尝试使用备用方案:', error);
                // 使用备用音频方案
                const fallbackSuccess = await initFallbackAudio();
                if (fallbackSuccess) {
                    useFallback = true;
                    console.log('已切换到备用音频方案');
                } else {
                    throw new Error('所有音频方案都失败了');
                }
            }
        }
        
        // 播放基准音 A4
        async function playReference() {
            try {
                await initAudio();
                
                if (useFallback) {
                    // 使用备用方案播放
                    playNoteWithFallback(440, 1.0);
                } else {
                    // 确保音频上下文处于运行状态
                    if (Tone.context.state !== 'running') {
                        await Tone.start();
                    }
                    synth.triggerAttackRelease("A4", "1n");
                }
                
                updateStatus("播放基准音 A4 (440Hz)");
            } catch (error) {
                console.error('播放基准音时出错:', error);
                updateStatus("播放失败，请重试");
            }
        }
        
        // 开始训练
        async function startTraining() {
            if (isTraining) return;
            
            try {
                updateStatus("正在初始化音频...");
                await initAudio();
                
                // 确保音频上下文已启动
                if (!useFallback && Tone.context.state !== 'running') {
                    await Tone.start();
                }
                
                isTraining = true;
                const audioMethod = useFallback ? "(备用音频)" : "(Tone.js)";
                updateStatus(`训练开始！${audioMethod}`);
                document.getElementById('intervalDisplay').style.display = 'block';
                 
                 await playNextInterval();
            } catch (error) {
                console.error('启动训练时出错:', error);
                updateStatus("启动失败，请重试");
            }
        }
        
        // 停止训练
        function stopTraining() {
            isTraining = false;
            clearTimeout(intervalTimer);
            clearInterval(progressTimer);
            updateStatus("训练已停止");
            document.getElementById('intervalDisplay').style.display = 'none';
            document.getElementById('progressFill').style.width = '0%';
        }
        
        // 播放下一个音程
        async function playNextInterval() {
            if (!isTraining) return;
            
            try {
                // 随机选择音程
                const intervalNames = Object.keys(intervals);
                const randomInterval = intervalNames[Math.floor(Math.random() * intervalNames.length)];
                const semitones = intervals[randomInterval];
                
                // 基准音 A4
                const baseNote = "A4";
                const baseFreq = 440;
                
                // 计算第二个音的频率
                const secondFreq = baseFreq * Math.pow(2, semitones / 12);
                const secondNote = frequencyToNote(secondFreq);
                
                console.log(`播放音程: ${randomInterval} (${baseNote} → ${secondNote})`);
                
                // 播放音程 (先播放基准音，然后播放第二个音)
                if (useFallback) {
                    // 使用备用方案播放
                    const baseFreq = noteToFrequency(baseNote);
                    const secondFreq = noteToFrequency(secondNote);
                    
                    playNoteWithFallback(baseFreq, 0.5);
                    setTimeout(() => {
                        if (isTraining) {
                            playNoteWithFallback(secondFreq, 0.5);
                        }
                    }, 600);
                } else {
                    // 确保音频上下文处于运行状态
                    if (Tone.context.state !== 'running') {
                        await Tone.start();
                    }
                    
                    synth.triggerAttackRelease(baseNote, "4n");
                    setTimeout(() => {
                        if (isTraining) {
                            synth.triggerAttackRelease(secondNote, "4n");
                        }
                    }, 600);
                }
                
                updateStatus("正在播放音程...");
                
                // 显示进度条
                startProgressBar();
                
                // 延迟显示答案
                setTimeout(() => {
                    if (isTraining) {
                        showAnswer(randomInterval, `${baseNote} → ${secondNote}`);
                        
                        // 继续下一题
                        intervalTimer = setTimeout(playNextInterval, trainingSpeed * 1000);
                    }
                }, trainingSpeed * 1000 - 1000);
            } catch (error) {
                console.error('播放音程时出错:', error);
                updateStatus("播放失败，请重试");
                stopTraining();
            }
        }
        
        // 频率转音符名 (简化版)
        function frequencyToNote(freq) {
            const notes = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B'];
            const A4 = 440;
            const C0 = A4 * Math.pow(2, -4.75);
            
            if (freq > C0) {
                const h = Math.round(12 * Math.log2(freq / C0));
                const octave = Math.floor(h / 12);
                const n = h % 12;
                return notes[n] + octave;
            }
            return "A4";
        }
        
        // 显示答案
        function showAnswer(intervalName, notes) {
            document.getElementById('intervalName').textContent = intervalName;
            document.getElementById('intervalNotes').textContent = notes;
            updateStatus("答案已显示，准备下一题...");
        }
        
        // 更新状态
        function updateStatus(message) {
            document.getElementById('status').textContent = message;
        }
        
        // 更新训练速度
        function updateSpeed(value) {
            trainingSpeed = parseInt(value);
            document.getElementById('speedValue').textContent = value + ' 秒/题';
        }
        
        // 进度条动画
        function startProgressBar() {
            let progress = 0;
            const increment = 100 / (trainingSpeed * 10);
            
            progressTimer = setInterval(() => {
                progress += increment;
                if (progress >= 100) {
                    progress = 100;
                    clearInterval(progressTimer);
                }
                document.getElementById('progressFill').style.width = progress + '%';
            }, 100);
        }
        
        // 检查浏览器音频支持
        function checkAudioSupport() {
            const hasWebAudio = !!(window.AudioContext || window.webkitAudioContext);
            const hasToneJS = typeof Tone !== 'undefined';
            
            if (!hasWebAudio) {
                updateStatus("❌ 浏览器不支持音频播放");
                return false;
            }
            
            if (!hasToneJS) {
                updateStatus("⚠️ Tone.js加载失败，将使用备用音频方案");
            }
            
            return true;
        }
        
        // 页面加载时初始化
        document.addEventListener('DOMContentLoaded', function() {
            if (checkAudioSupport()) {
                updateStatus("点击\"开始训练\"开始练习");
            }
            
            // 添加用户交互检测，确保音频上下文能够启动
            document.addEventListener('click', async function initUserInteraction() {
                try {
                    if (typeof Tone !== 'undefined' && Tone.context && Tone.context.state !== 'running') {
                        await Tone.start();
                        console.log('用户交互后Tone.js音频上下文已启动');
                    }
                    
                    // 也尝试启动原生音频上下文
                    if (window.AudioContext || window.webkitAudioContext) {
                        const testContext = new (window.AudioContext || window.webkitAudioContext)();
                        if (testContext.state === 'suspended') {
                            await testContext.resume();
                            console.log('用户交互后原生音频上下文已启动');
                        }
                        testContext.close();
                    }
                } catch (error) {
                    console.log('音频上下文启动失败:', error);
                }
                // 只需要执行一次
                document.removeEventListener('click', initUserInteraction);
            });
        });
    </script>
</body>
</html>